/*
 * BigInt.cpp
 *
 *  Created on: May 23, 2011
 *      Author: Manslaughter
 */

#include "BigInt.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <typeinfo>
#include <algorithm>    // for reverse() in itoa()
using namespace std;
using namespace APIAL;

/*
	Copy constructor
	Performs a deep copy (copies chunks array)
*/
BigInt::BigInt(const BigInt &original) {
	this->chunks = new BigInt::chunkType[original.capacity];
	this->capacity = original.capacity;
	this->size = original.size;
	memcpy(this->chunks, original.chunks, this->size*sizeof(BigInt::chunkType));
	this->normalized = original.normalized;
	this->positive = original.positive;
	this->carryBits = original.carryBits;
	this->nonCarryBits = original.nonCarryBits;
	this->nonCarryBitsMask = original.nonCarryBitsMask;
	this->carryBitsMask = original.carryBitsMask;
}

// TODO: Capacity should be specified in bits
/*
	Public constructor.  Capacity is the capacity of the
	chunks array.
*/
BigInt::BigInt(int capacity_) {
	this->capacity = capacity_;
    if (this->capacity > 0) {
        this->chunks = new chunkType[this->capacity];
    }
	memset (chunks,0,this->capacity*sizeof(chunkType));
	this->positive = true;
    this->normalized = true;
    this->size = 0;
    this->carryBits = 1;
	this->nonCarryBits = (sizeof(chunkType)*8)-carryBits;
	this->nonCarryBitsMask = ((chunkType)(-1))>>carryBits;
	this->carryBitsMask = (~nonCarryBitsMask);
}

/*
	Private testing constructor.
	@chunkSizeInBits The number of bits in a chunk.  This includes the 
		carry bits.
*/
BigInt::BigInt(int capacity_, int chunkSizeInBits) {
	this->capacity = capacity_;
    if (this->capacity > 0) {
        this->chunks = new chunkType[this->capacity];
    }
	memset (chunks,0,this->capacity*sizeof(chunkType));
	this->positive = true;
    this->normalized = true;
    this->size = 0;
    this->carryBits = 1;
	if (sizeof(chunkType)*8 < chunkSizeInBits || chunkSizeInBits <= carryBits) {
		assert(false);
	}
	this->nonCarryBits = chunkSizeInBits-carryBits;
	this->nonCarryBitsMask = (1<<nonCarryBits)-1;
	this->carryBitsMask = (~nonCarryBitsMask);
}

BigInt::~BigInt()
{
    delete [] chunks;
}

/*
  Sets the chunks array memory to 0.
*/
void BigInt::clear() {
	if (this->capacity > 0) {
		memset(this->chunks, 0, this->capacity*sizeof(chunkType));
	}
}

/*
	Resizes chunks and optionally copies values from old array to new array.
*/
void BigInt::resize(int newCapacity, bool copyValue) {
	if (this->capacity != newCapacity) {
		if (newCapacity == 0) {
			// Free the old chunks
			this->capacity = 0;
			delete [] chunks;
		} else {
			// Allocate new array (smaller or larger)
			chunkType* newChunks = new chunkType[newCapacity];

			// Copy contents
			if (copyValue) {
				int copySize = this->size;
				if (newCapacity < this->size) {
					copySize = newCapacity;
					this->size = copySize;
				}
				memcpy(newChunks,this->chunks,copySize*sizeof(chunkType));
			}

			// Free the previous array
			if (this->capacity > 0) {
				delete [] this->chunks;
			}
			this->chunks = newChunks;
			this->capacity = newCapacity;
		}
	}
}

BigInt& BigInt::operator=(const BigInt& bi)
{
	if (this != &bi)
	{
		BigInt::chunkType* newArray = new BigInt::chunkType[bi.capacity];

		memcpy(newArray,bi.chunks,bi.size * sizeof(BigInt::chunkType));

		this->positive = bi.positive;
		this->size = bi.size;
		this->capacity = this->capacity;

		delete[] this->chunks;

		this->chunks = newArray;
	}

	return *this;
}

bool APIAL::IsPositive(BigInt *bi)
{ 
	return bi->positive; 
}